home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / packdisk.arc / PACKDISK.C < prev    next >
C/C++ Source or Header  |  1991-04-28  |  8KB  |  336 lines

  1. //
  2. // PackDisk v1.2, 9/28/90.  Copyright 1990, Brad Davis.
  3. // Unlimited distribution of unmodified source and executable permitted.
  4. // bugs, suggestions, etc to bradd@gssc
  5. //
  6. // Suggested compilation for Microsoft C 6.0:
  7. // cl /AC /W3 /WX packdisk.c setargv /link /NOE
  8. //
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <process.h>
  14. #include <dos.h>
  15. #include <types.h>
  16. #include <stat.h>
  17. #include <fcntl.h>
  18. #include <io.h>
  19. #include <conio.h>
  20.  
  21. typedef struct fINFO {
  22.    char *name;
  23.    long size;
  24.    struct fINFO *next;
  25. } FINFO;
  26.  
  27. typedef struct diskfree_t DISKFREE;
  28. typedef struct stat FILESTAT;
  29.  
  30. static char *shell;
  31.  
  32. //
  33. // Insert a new file into our list, sorting by size as we go.
  34. //
  35. void insert (
  36.    FINFO **list,
  37.    FINFO *new
  38. )
  39. {
  40.    auto FINFO *cur;
  41.    auto FINFO **prev;
  42.  
  43.    // Traverse the list until we find a file that is smaller.
  44.    for (prev = list, cur = *list;
  45.     cur;
  46.     prev = &cur->next, cur = cur->next)
  47.    {
  48.       // New one is bigger than this one ?
  49.       if (new->size > cur->size)
  50.       {
  51.      new->next = cur;        // Yes, link small one below new
  52.      *prev = new;            // and bigger one to new one
  53.      return;
  54.       }
  55.    }
  56.  
  57.    // At the end of the list, so append the new (and smallest) one
  58.    *prev = new;
  59.    new->next = 0;
  60.    return;
  61. }
  62.  
  63.  
  64. //
  65. // Copy the files over so that wasted space is minimized
  66. //
  67. int copy (
  68.     FINFO **list,
  69.     char *dest,
  70.     int cluster_size,
  71.     int avail_clusters
  72. )
  73. {
  74.     auto FINFO *cur;
  75.     auto FINFO **prev;
  76.     auto int remaining;
  77.     auto int err;
  78.     auto int clusters;
  79.     auto char destname[128];
  80.  
  81.     // Set the clusters-remaining count
  82.     remaining = avail_clusters;
  83.  
  84.     // Traverse the list
  85.     for (prev = list, cur = *list;
  86.     cur && remaining;
  87.     )
  88.     {
  89.        // Cache size of this file in clusters
  90.        clusters = (int) ((cur->size + (cluster_size - 1)) / cluster_size);
  91.  
  92.        // Construct file name on destination device
  93.        strcpy (destname, dest);
  94.        strcat (destname, cur->name);
  95.  
  96.        // Is this file too big to fit on the disk at all?
  97.        if ( clusters > avail_clusters)
  98.        {
  99.       printf ("Warning: %s too large (%ld) for destination media.\n",
  100.          cur->name, cur->size);
  101.  
  102.       // Step to next in list
  103.       prev = &cur->next;
  104.       cur = cur->next;
  105.       continue;
  106.        }
  107.  
  108.        // Copy file if it will fit
  109.        if (clusters <= remaining)
  110.        {
  111.       // Create the dest file to see if the directory can hold it
  112.       err = open (destname, O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
  113.       if (err == -1)
  114.       {
  115.          printf ("    Root directory of disk is full (%ld bytes wasted)\n",
  116.          (long) cluster_size * remaining);
  117.           return (0);    // Upper level should not see as an error
  118.       }
  119.       if (close (err) == -1)
  120.       {
  121.          printf ("Error creating directory entry for %s\n", cur->name);
  122.          return (1);
  123.       }
  124.  
  125.       // Copy this one over
  126.       printf ("%8ld %s...", cur->size, cur->name);
  127.       err = spawnlp (P_WAIT, shell, shell, "/C", "COPY", cur->name, dest,
  128.         ">", "NUL", (char *) 0);
  129.       if (err)
  130.       {
  131.          printf ("  Error %d during copy\n", err);
  132.          return (1);
  133.       }
  134.       printf ("\n");
  135.  
  136.       // Reduce clusters remaining count
  137.       remaining -= clusters;
  138.  
  139.       // Now delete it from the list
  140.       *prev = cur->next;        // previous points to next
  141.  
  142.       // Do NOT step to the next entry
  143.       cur = *prev;
  144.       continue;
  145.        } else
  146.        {
  147.       // Step to next in list
  148.       prev = &cur->next;
  149.       cur = cur->next;
  150.       continue;
  151.        }
  152.     }
  153.  
  154.     // Let the user know if any space remains on the disk
  155.     if (remaining)
  156.     {
  157.     printf ("%ld bytes remain on disk\n", (long) cluster_size * remaining);
  158.     }
  159.  
  160.     return (0);        // No error for now.
  161. }
  162.  
  163.  
  164. #ifdef DEBUG
  165. //
  166. // Print out the list in order
  167. //
  168. void printlist (
  169.    FINFO *list,
  170. )
  171. {
  172.    auto FINFO *cur;
  173.  
  174.    for (cur = list;
  175.     cur;
  176.     cur = cur->next)
  177.    {
  178.     printf ("%8ld %s\n", cur->size, cur->name);
  179.    }
  180. }
  181. #endif
  182.  
  183.  
  184. //
  185. // Prompt for a new disk
  186. //
  187. int newdisk (
  188.    int drive,
  189.    int *cluster_size,
  190.    int *avail_clusters
  191. )                // returns 0 if all is well
  192. {
  193.     auto DISKFREE df;
  194.     auto int err;
  195.     static char *dest = "X:";
  196.     static char *destdir = "X:\\";
  197.     auto int key;
  198.  
  199.     do {
  200.     printf ("\n\nInsert disk for %c: and hit return (or Dir/Erase/Format/Label/Shell).\n",
  201.         drive + '@');
  202.     key = tolower (getch ());
  203.     *destdir = *dest = (char) (drive + '@');
  204.     if (key == 'd') {
  205.         err = spawnlp (P_WAIT, shell, shell, "/C", "DIR", dest, (char *) 0);
  206.     }
  207.     if (key == 'e') {
  208.         err = spawnlp (P_WAIT, shell, shell, "/C", "DEL", destdir,
  209.         (char *) 0);
  210.     }
  211.     if (key == 'f') {
  212.         err = spawnlp (P_WAIT, "QFORMAT", "QFORMAT", dest, (char *) 0);
  213.     }
  214.     if ( (key == 'l') || (key == 'f') ) {
  215.         err = spawnlp (P_WAIT, "LABEL", "LABEL", dest, (char *) 0);
  216.     }
  217.     if (key == 's') {
  218.         err = spawnlp (P_WAIT, shell, shell, (char *) 0);
  219.     }
  220.     }
  221.     while (key != '\r');
  222.  
  223.     // Find out how much space is available on dest
  224.     err = _dos_getdiskfree (drive , &df);
  225.     if (err)
  226.     {
  227.     return (1);
  228.     }
  229.  
  230.     // Set the number of clusters for each file
  231.     *cluster_size = df.sectors_per_cluster * df.bytes_per_sector;
  232.     *avail_clusters = df.avail_clusters;
  233.  
  234.     printf ("    Disk has %ld bytes free (%d x %d byte clusters)\n",
  235.     *avail_clusters * (long) *cluster_size,
  236.     *avail_clusters, *cluster_size);
  237.  
  238.     return (0);
  239. }
  240.  
  241.  
  242. void main (
  243.     int argc,
  244.     char *argv[]
  245. )
  246. {
  247.     auto int err;
  248.     auto FINFO *list;
  249.     auto FINFO *files;
  250.     auto FINFO *fptr;
  251.     auto int drive;
  252.     auto int file;
  253.     auto int cluster_size;
  254.     auto int avail_clusters;
  255.     auto int number_files;
  256.     auto FILESTAT filestat;
  257.  
  258.     // Validate the command line
  259.     if (argc < 3
  260.     || strlen (argv[argc - 1]) != 2
  261.     || argv[argc - 1][1] != ':'
  262.     || (drive = toupper(argv[argc - 1][0]) - '@') < 0
  263.     )
  264.     {
  265.     printf ("PackDisk v1.2, 9/28/90.  Copyright 1990, Brad Davis.\n\n");
  266.     printf ("Usage:\n");
  267.     printf ("   packdisk file [file [...]] D:\n\n");
  268.     printf ("Copies source files to disks in the destination drive,\n");
  269.     printf ("using the minimum number of disks.\n\n");
  270.     exit (0);
  271.     }
  272.  
  273.     shell = getenv ("COMSPEC");
  274.     if (!shell)
  275.     {
  276.     printf ("Cannot locate COMSPEC\n");
  277.     exit (1);
  278.     }
  279.  
  280.     // Determine the number of source files and allocate storage for them
  281.     number_files = argc - 1 - 1;    // 0 = our name, last = dest
  282.  
  283.     files = (FINFO *) malloc (sizeof (FINFO) * number_files);
  284.     if (!files)
  285.     {
  286.     printf ("Error %d allocating for file list.\n", err);
  287.     exit (1);
  288.     }
  289.  
  290.     // Build a list of all files
  291.     for (file = 0, fptr = &files[0]; file < number_files; file++, fptr++)
  292.     {
  293.     fptr->name = argv[file + 1];
  294.  
  295.     // Get info on the file
  296.     err = stat (fptr->name, &filestat);
  297.     if (err)
  298.     {
  299.          printf ("Error %d reading %s.\n", err, fptr->name);
  300.          exit (1);
  301.     }
  302.     fptr->size = filestat.st_size;
  303.     fptr->next = (FINFO *) 0;
  304.     }
  305.  
  306.     // Build a list of the files sorted by size (decreasing)
  307.     list = (FINFO *) 0;
  308.     for (file = 0, fptr = files; file < number_files; file++, fptr++)
  309.     {
  310.     // Add it to our list
  311.     insert (&list, fptr);
  312.     }
  313.  
  314. #ifdef DEBUG
  315.     printlist (list);
  316. #endif
  317.  
  318.     while (list)
  319.     {
  320.     err = newdisk(drive, &cluster_size, &avail_clusters);
  321.     if (err)
  322.     {
  323.         printf ("Error %d getting diskfree on drive %c:.\n",
  324.         err, drive + '@');
  325.     }
  326.  
  327.     // Copy files, return 0 if ok
  328.     err = copy (&list, argv[argc - 1], cluster_size, avail_clusters);
  329.     if (err)
  330.     {
  331.         printf ("Error %d during copying.\n", err);
  332.         exit(1);
  333.     }
  334.     }
  335. }
  336.